#ifndef FFINCLUDE_H
#define FFINCLUDE_H
#include <QObject>

extern "C" {
    #include "libavutil/avstring.h"
    #include "libavutil/eval.h"
    #include "libavutil/mathematics.h"
    #include "libavutil/pixdesc.h"
    #include "libavutil/imgutils.h"
    #include "libavutil/dict.h"
    #include "libavutil/parseutils.h"
    #include "libavutil/samplefmt.h"
    #include "libavutil/avassert.h"
    #include "libavutil/time.h"
    #include "libavutil/opt.h"
    #include "libavutil/bprint.h"
    #include "libavutil/display.h"
    #include "libavutil/mathematics.h"
    #include "libavutil/cpu.h"
    #include "libavutil/ffversion.h"
    #include "libavutil/version.h"

    #include "libavformat/avformat.h"
    #include "libavdevice/avdevice.h"
    #include "libavcodec/avfft.h"
    #include "libswresample/swresample.h"
    #include "libavresample/avresample.h"
    #include "libswscale/swscale.h"

    #include "libavfilter/avfilter.h"
    #include "libavfilter/buffersink.h"
    #include "libavfilter/buffersrc.h"
    #include "libpostproc/postprocess.h"
}

#include <SDL2/SDL.h>
#include <SDL2/SDL_thread.h>
#include <SDL2/SDL_video.h>

#include <inttypes.h>
#include <math.h>
#include <limits.h>
#include <signal.h>
#include <stdint.h>


const char program_name[] = "ffplay";
const int program_birth_year = 2003;

#define MAX_QUEUE_SIZE (15 * 1024 * 1024)
#define MIN_FRAMES 25
#define EXTERNAL_CLOCK_MIN_FRAMES 2
#define EXTERNAL_CLOCK_MAX_FRAMES 10

/* Minimum SDL audio buffer size, in samples. */
#define SDL_AUDIO_MIN_BUFFER_SIZE 512
/* Calculate actual buffer size keeping in mind not cause too frequent audio callbacks */
#define SDL_AUDIO_MAX_CALLBACKS_PER_SEC 30

/* Step size for volume control in dB */
#define SDL_VOLUME_STEP (0.75)

/* no AV sync correction is done if below the minimum AV sync threshold */
#define AV_SYNC_THRESHOLD_MIN 0.04
/* AV sync correction is done if above the maximum AV sync threshold */
#define AV_SYNC_THRESHOLD_MAX 0.1
/* If a frame duration is longer than this, it will not be duplicated to compensate AV sync */
#define AV_SYNC_FRAMEDUP_THRESHOLD 0.1
/* no AV correction is done if too big error */
#define AV_NOSYNC_THRESHOLD 10.0

/* maximum audio speed change to get correct sync */
#define SAMPLE_CORRECTION_PERCENT_MAX 10

/* external clock speed adjustment constants for realtime sources based on buffer fullness */
#define EXTERNAL_CLOCK_SPEED_MIN  0.900
#define EXTERNAL_CLOCK_SPEED_MAX  1.010
#define EXTERNAL_CLOCK_SPEED_STEP 0.001

/* we use about AUDIO_DIFF_AVG_NB A-V differences to make the average */
#define AUDIO_DIFF_AVG_NB   20

/* polls for possible required screen refresh at least this often, should be less than 1/fps */
#define REFRESH_RATE 0.01

/* NOTE: the size must be big enough to compensate the hardware audio buffersize size */
/* TODO: We assume that a decoded and resampled frame fits into this buffer */
#define SAMPLE_ARRAY_SIZE (8 * 65536)

#define CURSOR_HIDE_DELAY 1000000

#define USE_ONEPASS_SUBTITLE_RENDER 1


enum ShowMode {
    SHOW_MODE_NONE = -1, SHOW_MODE_VIDEO = 0, SHOW_MODE_WAVES, SHOW_MODE_RDFT, SHOW_MODE_NB
} ;


typedef struct MyAVPacketList {
    AVPacket pkt;
    struct MyAVPacketList *next;
    int serial;
} MyAVPacketList;

typedef struct PacketQueue {
    MyAVPacketList *first_pkt, *last_pkt;
    int nb_packets;
    int size;
    int64_t duration;
    int abort_request;
    int serial;
    SDL_mutex *mutex;
    SDL_cond *cond;        //用于阻塞模式读取
    AVPacket* flush_pkt;   //Flush帧，向队列压入此帧会自增serial
} PacketQueue;

#define VIDEO_PICTURE_QUEUE_SIZE 3
#define SUBPICTURE_QUEUE_SIZE 16
#define SAMPLE_QUEUE_SIZE 9
#define FRAME_QUEUE_SIZE FFMAX(SAMPLE_QUEUE_SIZE, FFMAX(VIDEO_PICTURE_QUEUE_SIZE, SUBPICTURE_QUEUE_SIZE))

typedef struct AudioParams {
    int freq;
    int channels;
    int64_t channel_layout;
    enum AVSampleFormat fmt;
    int frame_size;
    int bytes_per_sec;
} AudioParams;

typedef struct Clock {
    double pts;           /* clock base */
    double pts_drift;     /* clock base minus time at which we updated the clock */
    double last_updated;
    double speed;
    int serial;           /* clock is based on a packet with this serial */
    int paused;
    int *queue_serial;    /* pointer to the current packet queue serial, used for obsolete clock detection */
} Clock;

typedef struct Frame {
    AVFrame *frame;
    AVSubtitle sub;
    int serial;
    double pts;           /* presentation timestamp for the frame */
    double duration;      /* estimated duration of the frame */
    int64_t pos;          /* byte position of the frame in the input file */
    int width;
    int height;
    int format;
    AVRational sar;
    int uploaded;
    int flip_v;
} Frame;

typedef struct FrameQueue {
    Frame queue[FRAME_QUEUE_SIZE];
    int rindex;
    int windex;
    int size;
    int max_size;
    int keep_last;
    int rindex_shown;
    SDL_mutex *mutex;
    SDL_cond *cond;
    PacketQueue *pktq;
} FrameQueue;

enum AV_SYNC_TYPE{
    AV_SYNC_AUDIO_MASTER, /* default choice */
    AV_SYNC_VIDEO_MASTER,
    AV_SYNC_EXTERNAL_CLOCK, /* synchronize to an external clock */
};

typedef struct Decoder {
    AVPacket pkt;
    PacketQueue *queue;
    AVCodecContext *avctx;
    int pkt_serial;
    int finished;   //是否已解码完最后一帧
    int packet_pending;
    SDL_cond *empty_queue_cond;
    int64_t start_pts;
    AVRational start_pts_tb;
    int64_t next_pts;
    AVRational next_pts_tb;
    SDL_Thread *decoder_tid;
} Decoder;


class VideoPlayer;
struct PlayerInfo {
    //共享数据
    bool isLiveStream;          //是否为直播流
    double maxFrameDuration;    //单帧最大允许时长，超过此值将会在解码时丢弃
    bool demuxEof;              //解复用是否解完最后一包
    bool videoCodecEof;         //视频解码是否已解完最后一帧
    bool audioCodecEof;         //音频解码是否已解完最后一帧
    bool textCodecEof;          //字幕解码是否已解完最后一帧
    int frame_drops_early;
    int frame_drops_late;
    AV_SYNC_TYPE syncType;      //当前生效的音视频同步方式

    //demux
    AVFormatContext* formatContext;
    AVStream* videoStream;
    AVStream* audioStream;
    AVStream* textStream;

    //decode
    AVCodecContext* videoCodecContext;
    AVCodec* videoCodec;
    AVCodecContext* audioCodecContext;
    AVCodec* audioCodec;
    AVCodecContext* textCodecContext;
    AVCodec* textCodec;

    //render
    SDL_AudioDeviceID audioDevice;
    SDL_Renderer* renderer;
    SDL_Window* window;
    SDL_Texture *textTexture;
    SDL_Texture *videoTexture;

    //queue
    AVPacket flushPkt;
    FrameQueue videoFrameQueue;
    FrameQueue textFrameQueue;
    FrameQueue audioFrameQueue;
    PacketQueue textPacketQueue;
    PacketQueue videoPacketQueue;
    PacketQueue audioPacketQueue;

    //clock
    Clock*masterClock;
    Clock audioClock;
    Clock videoClock;
    Clock externalClock;                               


    //TODO: 线程中去掉
    int reqStop;                //是否需要停止
    int reqPause;               //是否需要暂停
    int reqforceRender;         //是否需要强制刷新视频帧
    bool reqQueueAttachments;   //是否需要缓存封面帧



    //decoder
    VideoPlayer* player;

    Decoder auddec;
    Decoder viddec;
    Decoder subdec;

    //用户可配置参数
    QString vcodecName;     //视频解码器名称
    QString acodecName;     //音频解码器名称
    const void* winId;      //视频渲染窗口句柄
    int volume;             //音量
    int muted;              //是否静音
    int rate;               //播放速度
    bool fill;              //是否按填充模式渲染视频
    int timeout;            //超时时间(ms)
    bool rtspWithTcp;       //RTSP拉流时使用TCP传输
    bool videoEnable;       //是否播放视频流
    bool audioEnable;       //是否播放音频流
    bool textEnable;        //是否播放字幕流


    const char *url;       //媒体源地址
    int xleft, ytop, width, height;  //渲染区域

    int isEof;
    AVInputFormat *iformat;
    AVFormatContext *ic;
    SDL_Texture* vis_texture;

    SDL_Thread *read_tid;
    SDL_Thread *render_tid;
    SDL_Window *window2;

    int last_paused;

    int seek_req;
    int seek_flags;
    int64_t seek_pos;
    int64_t seek_rel;
    int read_pause_return;


    int audio_stream;

    int av_sync_type;
    double audio_clock;
    int audio_clock_serial;
    double audio_diff_cum; /* used for AV difference average computation */
    double audio_diff_avg_coef;
    double audio_diff_threshold;
    int audio_diff_avg_count;
    AVStream *audio_st;

    int audio_hw_buf_size;
    uint8_t *audio_buf;
    uint8_t *audio_buf1;
    unsigned int audio_buf_size; /* in bytes */
    unsigned int audio_buf1_size;
    int audio_buf_index; /* in bytes */
    int audio_write_buf_size;

    struct AudioParams audio_src;
#if 1
    struct AudioParams audio_filter_src;
#endif
    struct AudioParams audio_tgt;
    struct SwrContext *swr_ctx;


    ShowMode show_mode;
    int16_t sample_array[SAMPLE_ARRAY_SIZE];
    int sample_array_index;
    int last_i_start;
    RDFTContext *rdft;
    int rdft_bits;
    FFTSample *rdft_data;
    int xpos;
    double last_vis_time;

    int subtitle_stream;
    AVStream *subtitle_st;

    double frame_timer;
    double frame_last_returned_time;
    double frame_last_filter_delay;
    int video_stream;
    AVStream *video_st;


    struct SwsContext *img_convert_ctx;
    struct SwsContext *sub_convert_ctx;


    int step;

#if 1
    int vfilter_idx;
    AVFilterContext *in_video_filter;   // the first filter in the video chain
    AVFilterContext *out_video_filter;  // the last filter in the video chain
    AVFilterContext *in_audio_filter;   // the first filter in the audio chain
    AVFilterContext *out_audio_filter;  // the last filter in the audio chain
    AVFilterGraph *agraph;              // audio filter graph
#endif

    int last_video_stream, last_audio_stream, last_subtitle_stream;

    SDL_cond *continue_read_thread;
};


int frame_queue_init(FrameQueue *f, PacketQueue *pktq, int max_size, int keep_last);
void frame_queue_destory(FrameQueue *f);
Frame *frame_queue_peek_current(FrameQueue *f);
Frame *frame_queue_peek_next(FrameQueue *f);
Frame *frame_queue_peek_last(FrameQueue *f);
Frame *frame_queue_peek_writable(FrameQueue *f, bool block=true);
Frame *frame_queue_peek_readable(FrameQueue *f, bool block=true);
void frame_queue_push(FrameQueue *f);
void frame_queue_next(FrameQueue *f);
void frame_queue_signal(FrameQueue *f);
int frame_queue_nb_remaining(FrameQueue *f);
int64_t frame_queue_last_pos(FrameQueue *f);
void frame_queue_unref_item(Frame *vp);

int packet_queue_init(PacketQueue *q);
void packet_queue_destroy(PacketQueue *q);
void packet_queue_start(PacketQueue *q,AVPacket* flush_pkt);
void packet_queue_abort(PacketQueue *q);
void packet_queue_flush(PacketQueue *q);
int packet_queue_get(PacketQueue *q, AVPacket *pkt, int block, int *serial);
int packet_queue_put(PacketQueue *q, AVPacket *pkt);
int packet_queue_put_nullpacket(PacketQueue *q, int stream_index);
int packet_queue_put_private(PacketQueue *q, AVPacket *pkt);

void init_clock(Clock *c, int *queue_serial);
double get_clock(Clock *c);
void set_clock_at(Clock *c, double pts, int serial, double time);
void set_clock(Clock *c, double pts, int serial);
void set_clock_speed(Clock *c, double speed);
void sync_clock_to_slave(Clock *c, Clock *slave);
double get_master_clock(PlayerInfo *is);   //TODO: 转移到线程中
int get_master_sync_type(PlayerInfo *is);
void check_external_clock_speed(PlayerInfo *is);

QString avErrorCodeToString(int errCode);

#endif // FFINCLUDE_H
